/*
 * $Id:
 *
 * Copyright (C) 2011 Refiner Inc.
 * All right reserved
 *
 *============================================================
 * +rVPN Stack : AppIF (Socket Base Interface)
 *============================================================
 * abstract: This module provides TCP/IP stack callback
 * author  : MURATA
 * history :
 *
 */

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <rts_socket.h>
#include "rsi_apisock.h"
#include "rsi_tcpipif.h"

/* エラー応答送信 */
void rsi_tif_senderr(rsi_tifct_t* ct, int err)
{
    rvs_api_send_t* smsg = NULL;

    smsg = rvs_make_msg(RAPI_M_RESP(ct->msgcode), ct->seqno, -1);
    if (smsg == NULL) {
        LOGE("%s: cannot make smsg\n", __FUNCTION__);
        goto serrexit;
    }

    if (rvs_add_errno(smsg, err) < 0) {
        LOGE("%s: cannot set errno(%d)\n", __FUNCTION__, err);
        goto serrexit;
    }

    rsi_apisock_send(ct->rsock, smsg);

serrexit:
    if (smsg) rvs_free(smsg);
}


static rvs_api_send_t* check_make_smsg(rsi_tifct_t* ct, int result)
{
    rvs_api_msg_t* rmsg = NULL;
    rvs_api_send_t* smsg = NULL;

    /* 受信メッセージのチェック */
    if (ct->rsock == NULL) {
        LOGE("%s: rsock is NULL\n", __FUNCTION__);
        goto chkerr;
    }
    rmsg = rsi_apisock_rmsg(ct->rsock);
    if (rmsg == NULL || rmsg->header == NULL) {
        LOGE("%s: cannot get recv msg\n", __FUNCTION__);
        goto chkerr;
    }
    if (rmsg->header->msgcode != ct->msgcode ||
              rmsg->header->seqno != ct->seqno) {
        LOGE("%s: msgcode(%04x:%04x) or seqno(%d:%d) is invalid.\n",
                   __FUNCTION__, rmsg->header->msgcode, ct->msgcode,
                   rmsg->header->seqno, ct->seqno);
        goto chkerr;
    }
    rsi_apisock_release(ct->rsock);
    rmsg = NULL;

    /* 送信メッセージの作成 */
    if (result >= 0) {
        smsg = rvs_make_msg(RAPI_M_RESP(ct->msgcode), ct->seqno, result);
    } else {
        rsi_tif_senderr(ct, -result);
    }

chkerr:
    if (rmsg) {
        rsi_apisock_release(ct->rsock);
    }
    return smsg;
}

static void send_msg_noparam(int msgcode, int result, void* context)
{
    rsi_tifct_t* ct = (rsi_tifct_t*)context;
    rvs_api_send_t* smsg = NULL;

    if (ct->msgcode != msgcode) {
        goto noperr;
    }

    /* 送信メッセージの作成 */
    smsg = check_make_smsg(ct, result);
    if (smsg == NULL) {
        goto noperr;
    }

    rsi_apisock_send(ct->rsock, smsg);

noperr:
    if (smsg) {
        rvs_free(smsg);
    }
    rsi_tif_free(ct);
}

/* socket応答送信 */
void rsi_cb_socket(int result, void* context)
{
    rsi_tifct_t* ct = (rsi_tifct_t*)context;
    rvs_api_send_t* smsg = NULL;

    LOGD("%s: Called(result=%d)\n", __FUNCTION__, result);

    if (ct->msgcode != RAPI_M_SOCKET) {
        goto sockerr;
    }

    /* 送信メッセージの作成 */
    smsg = check_make_smsg(ct, result);
    if (smsg == NULL) {
        goto sockerr;
    }
    smsg->header.status = 0;

    /* パラメータ設定 */
    if (rvs_add_rsock(smsg, result) < 0) {
        rsi_tif_senderr(ct, EIO);
        goto sockerr;
    }

    rsi_apisock_send(ct->rsock, smsg);

sockerr:
    if (smsg) {
        rvs_free(smsg);
    }
    rsi_tif_free(ct);
}

void rsi_cb_close(int result, void *context)
{
    LOGD("%s: Called(result=%d)\n", __FUNCTION__, result);

    send_msg_noparam(RAPI_M_CLOSE, result, context);
}

void rsi_cb_bind(int result, void *context)
{
    LOGD("%s: Called(result=%d)\n", __FUNCTION__, result);

    send_msg_noparam(RAPI_M_BIND, result, context);
}

void rsi_cb_listen(int result, void *context)
{
    LOGD("%s: Called(result=%d)\n", __FUNCTION__, result);

    send_msg_noparam(RAPI_M_LISTEN, result, context);
}

void rsi_cb_connect(int result, void *context)
{
    LOGD("%s: Called(result=%d)\n", __FUNCTION__, result);

    send_msg_noparam(RAPI_M_CONNECT, result, context);
}

void rsi_cb_accept(struct sockaddr *addr, socklen_t *addrlen, int result, void *context)
{
    rsi_tifct_t* ct = (rsi_tifct_t*)context;
    rvs_api_send_t* smsg = NULL;

    LOGD("%s: Called(result=%d)\n", __FUNCTION__, result);

    if (ct->msgcode != RAPI_M_ACCEPT) {
        goto acpterr;
    }

    /* 送信メッセージの作成 */
    smsg = check_make_smsg(ct, result);
    if (smsg == NULL) {
        goto acpterr;
    }
    smsg->header.status = 0;

    /* ソケット番号の追加 */
    if (rvs_add_rsock(smsg, result) < 0) {
        goto acpterr;
    }

    /* アドレスの追加 */
    if (rvs_add_addr(smsg, addr) < 0) {
        goto acpterr;
    }

    rsi_apisock_send(ct->rsock, smsg);

acpterr:
    if (smsg) {
        rvs_free(smsg);
    }
    rsi_tif_free(ct);
}

void rsi_cb_send(int result, void *context)
{
    LOGD("%s: Called(result=%d)\n", __FUNCTION__, result);

    send_msg_noparam(RAPI_M_SEND, result, context);
}

void rsi_cb_recv(void *buf, int result, void *context)
{
    rsi_tifct_t* ct = (rsi_tifct_t*)context;
    rvs_api_send_t* smsg = NULL;

    LOGD("%s: Called(result=%d)\n", __FUNCTION__, result);

    if (ct->msgcode != RAPI_M_RECV) {
        goto recverr;
    }

    /* 送信メッセージの作成 */
    smsg = check_make_smsg(ct, result);
    if (smsg == NULL) {
        goto recverr;
    }
    if (result > 0) {
        smsg->header.status = 0;
    }

    /* 受信データを追加する */
    if ((result > 0) && (rvs_add_data(smsg, buf, result) < 0)) {
        goto recverr;
    }

    rsi_apisock_send(ct->rsock, smsg);

recverr:
    if (smsg) {
        rvs_free(smsg);
    }
    rsi_tif_free(ct);
}

void rsi_cb_sendto(int result, void *context)
{
    LOGD("%s: Called(result=%d)\n", __FUNCTION__, result);

    send_msg_noparam(RAPI_M_SENDTO, result, context);
}

void rsi_cb_recvfrom(void *buf, struct sockaddr *from, socklen_t *fromlen, int result, void *context)
{
    rsi_tifct_t* ct = (rsi_tifct_t*)context;
    rvs_api_send_t* smsg = NULL;

    LOGD("%s: Called(result=%d)\n", __FUNCTION__, result);

    if (ct->msgcode != RAPI_M_RECVFROM) {
        goto rvfrerr;
    }

    /* 送信メッセージの作成 */
    smsg = check_make_smsg(ct, result);
    if (smsg == NULL) {
        goto rvfrerr;
    }
    if (result > 0) {
        smsg->header.status = 0;
    }

    /* アドレスの追加 */
    if (rvs_add_addr(smsg, from) < 0) {
        goto rvfrerr;
    }

    /* 受信データを追加する */
    if ((result > 0) && (rvs_add_data(smsg, buf, result) < 0)) {
        goto rvfrerr;
    }

    rsi_apisock_send(ct->rsock, smsg);

rvfrerr:
    if (smsg) {
        rvs_free(smsg);
    }
    rsi_tif_free(ct);
}

void rsi_cb_select(fd_set *in, fd_set *ou, fd_set *ex, int result, void *context)
{
    rsi_tifct_t* ct = (rsi_tifct_t*)context;
    rvs_api_send_t* smsg = NULL;
    select_args_t* sargs = (select_args_t*)ct->args;

//    LOGD("%s: Called(result=%d)\n", __FUNCTION__, result);
//    LOGD("%s: Called(result=%d, in=0x%x,ct=%p)\n", __FUNCTION__, result,
//#ifndef LINUX
//              in->fds_bits[0], context);
//#else
//              in->__fds_bits[0], context);
//#endif

    if (ct->msgcode != RAPI_M_SELECT) {
        LOGE("%s: Recv msg is not SELECT(0x%04x)\n", __FUNCTION__, ct->msgcode);
        goto selerr;
    }

    if (sargs == NULL) {
        LOGE("%s: args = NULL\n", __FUNCTION__);
        goto selerr;
    }

    /* 送信メッセージの作成 */
    //LOGD("@@@@@ %s: >> check_make_smsg(ct=%p, result=%d)\n", __FUNCTION__, ct, result);
    smsg = check_make_smsg(ct, result);
    //LOGD("@@@@@ %s: << check_make_smsg() smsg=%p\n", __FUNCTION__, smsg);
    if (smsg == NULL) {
        goto selerr;
    }

    /* fdsetの追加 */
    if (rvs_add_fdsets(smsg, sargs->nfds, in, ou, ex) < 0) {
        LOGE("%s: cannot set args(fd_set)\n", __FUNCTION__);
        goto selerr;
    }

    rsi_apisock_send(ct->rsock, smsg);

selerr:
    if (smsg) {
        rvs_free(smsg);
    }
    rsi_tif_free(ct);

//    LOGD("@@@@@ %s: Return(result=%d, in=0x%x,ct=%p)\n", __FUNCTION__, result,
//#ifndef LINUX
//              in->fds_bits[0], context);
//#else
//              in->__fds_bits[0], context);
//#endif
}

void rsi_cb_ioctl(void* arg, int arglen, int result, void *context)
{
    rsi_tifct_t* ct = (rsi_tifct_t*)context;
    rvs_api_send_t* smsg = NULL;

    LOGD("%s: Called(result=%d)\n", __FUNCTION__, result);

    if ((ct->msgcode != RAPI_M_IOCTL) && (ct->msgcode != RAPI_M_FCNTL)) {
        goto iocerr;
    }

    /* 送信メッセージの作成 */
    smsg = check_make_smsg(ct, result);
    if (smsg == NULL) {
        goto iocerr;
    }

    /* パラメータの追加 */
    if (arg) {
        if (ct->msgcode == RAPI_M_IOCTL) {
            if (rvs_add_value(smsg, arg, arglen) < 0) {
                goto iocerr;
            }
        } else {
            rvs_api_msg_t* msg = rsi_apisock_rmsg(ct->rsock);
            if (msg == NULL) {
                goto iocerr;
            }
            if (msg->option && (msg->option->Integer == F_GETFL)) {
                long val;
                if (*(int*)arg) {
                    val = O_NONBLOCK;
                } else {
                    val = 0;
                }
                if (rvs_add_value(smsg, &val, sizeof(long)) < 0) {
                    /* 2011.9.16 解放し忘れ? */
                    rsi_apisock_release(ct->rsock);
                    goto iocerr;
                }
            }
            rsi_apisock_release(ct->rsock);
        }
    }

    rsi_apisock_send(ct->rsock, smsg);

iocerr:
    if (smsg) {
        rvs_free(smsg);
    }
    rsi_tif_free(ct);
}

void rsi_cb_getpeername(struct sockaddr *name, socklen_t *namelen, int result, void *context)
{
    /* not supported */
}

void rsi_cb_getsockname(struct sockaddr *name, socklen_t *namelen, int result, void *context)
{
    rsi_tifct_t* ct = (rsi_tifct_t*)context;
    rvs_api_send_t* smsg = NULL;

    LOGD("%s: Called(result=%d)\n", __FUNCTION__, result);

    if (ct->msgcode != RAPI_M_GETSOCKNAME) {
        goto gsnerr;
    }

    /* 送信メッセージの作成 */
    smsg = check_make_smsg(ct, result);
    if (smsg == NULL) {
        goto gsnerr;
    }

    /* アドレスの追加 */
    if (rvs_add_addr(smsg, name) < 0) {
        goto gsnerr;
    }

    rsi_apisock_send(ct->rsock, smsg);

gsnerr:
    if (smsg) {
        rvs_free(smsg);
    }
    rsi_tif_free(ct);
}

void rsi_cb_getsockopt(void *val, socklen_t *avalsize, int result, void *context)
{
    rsi_tifct_t* ct = (rsi_tifct_t*)context;
    rvs_api_send_t* smsg = NULL;

    LOGD("%s: Called(result=%d)\n", __FUNCTION__, result);

    if (ct->msgcode != RAPI_M_GETSOCKOPT) {
        goto gsoerr;
    }

    /* 送信メッセージの作成 */
    smsg = check_make_smsg(ct, result);
    if (smsg == NULL) {
        goto gsoerr;
    }

    /* オプション値の設定 */
    if (val) {
        if (rvs_add_value(smsg, val, *avalsize) < 0) {
            goto gsoerr;
        }
    }

    rsi_apisock_send(ct->rsock, smsg);

gsoerr:
    if (smsg) {
        rvs_free(smsg);
    }
    rsi_tif_free(ct);
}

void rsi_cb_setsockopt(int result, void *context)
{
    LOGD("%s: Called(result=%d)\n", __FUNCTION__, result);

    send_msg_noparam(RAPI_M_SETSOCKOPT, result, context);
}

void rsi_cb_shutdown(int result, void *context)
{
    LOGD("%s: Called(result=%d)\n", __FUNCTION__, result);

    send_msg_noparam(RAPI_M_SHUTDOWN, result, context);
}

void rsi_cb_getlocalif(struct sockaddr* addr, socklen_t* addrlen, int result, void *context)
{
    rsi_tifct_t* ct = (rsi_tifct_t*)context;
    rvs_api_send_t* smsg = NULL;

    LOGD("%s: Called(result=%d)\n", __FUNCTION__, result);

    if (ct->msgcode != RAPI_M_GETLOCALIF) {
        goto gtiferr;
    }

    /* 送信メッセージの作成 */
    smsg = check_make_smsg(ct, result);
    if (smsg == NULL) {
        goto gtiferr;
    }
    smsg->header.status = 0;

    /* アドレスの追加 */
    if (rvs_add_addr(smsg, addr) < 0) {
        goto gtiferr;
    }

    rsi_apisock_send(ct->rsock, smsg);

gtiferr:
    if (smsg) {
        rvs_free(smsg);
    }
    rsi_tif_free(ct);

}

void rsi_cb_getvifroute(int vifno, int result, void *context)
{
    rsi_tifct_t* ct = (rsi_tifct_t*)context;
    rvs_api_send_t* smsg = NULL;

    LOGD("%s: Called(vifno=%d)\n", __FUNCTION__, vifno);

    if (ct->msgcode != RAPI_M_GETVIFROUTE) {
        goto gtiferr;
    }

    /* 送信メッセージの作成 */
    smsg = check_make_smsg(ct, result);
    if (smsg == NULL) {
        goto gtiferr;
    }
    smsg->header.status = 0;

    /* アドレスの追加 */

    if (rvs_add_vifno(smsg, vifno) < 0) {
        goto gtiferr;
    }

    rsi_apisock_send(ct->rsock, smsg);

gtiferr:
    if (smsg) {
        rvs_free(smsg);
    }
    rsi_tif_free(ct);

}

void rsi_cb_statuscheck(rvs_status_t* statusp, rvs_error_t* errorp, int result, void *context)
{
    rsi_tifct_t* ct = (rsi_tifct_t*)context;
    rvs_api_send_t* smsg = NULL;

    LOGD("%s: Called(result=%d)\n", __FUNCTION__, result);

    if (ct->msgcode != RAPI_M_STATUSCHECK) {
        goto schkerr;
    }

    /* 送信メッセージの作成 */
    smsg = check_make_smsg(ct, result);
    if (smsg == NULL) {
        goto schkerr;
    }
    smsg->header.status = 0;

    /* ステータス情報の追加 */
    if (rvs_add_statinfo(smsg, statusp) < 0) {
        goto schkerr;
    }

    /* エラー情報の追加 */
    if (errorp && errorp->rtype) {
        if (rvs_add_errinfo(smsg, errorp) < 0) {
            goto schkerr;
        }
    }

    rsi_apisock_send(ct->rsock, smsg);

schkerr:
    if (smsg) {
        rvs_free(smsg);
    }
    rsi_tif_free(ct);

}


